package main

import "fmt"

//闭包是函数和它所引用的环境，也就是闭包=函数+引用环境
//另一种理解：如果一个函数里面的内部函数引用了外层函数的变量，那么我们就可以认为这个函数是闭包函数了。
//闭包只能通过匿名函数实现，我们可以把闭包看作是有状态的匿名函数，反过来，如果匿名函数引用了外部变量，就形成了一个闭包。
//官方解释：闭包是一个函数值，它引用了其函数体之外的变量。该函数可以访问并赋予其引用的变量的值，换句话说，该函数被这些变量“绑定”在一起。

//记忆：函数名 (参数) 返回值类型 。返回值类型是在小括号后，大括号前

//先看一个简单函数的定义，注意它的返回值，是一个简单的int
func add(x int, y int) int {
	return x + y
}

//返回值是一个函数的函数
//注意声明的写法。个人理解是：先要返回一个函数。就需要写明，这个被返回的函数的，完整的参数类型和返回值类型。比如下面的 func(a int) int
func add1() func(int) int {
	var x int //初始为0
	//它返回一个匿名函数
	return func(a int) int {
		x += a   //引用外层函数变量 x，所以形成了闭包
		return x //返回int
	}
}

func main() {
	//add1()这个函数，返回了一个匿名函数。f1这个变量接收了这个匿名函数
	f1 := add1()
	f2 := add1()

	//简单理解：上面的f1得到了一个匿名函数，也同时也获得它的上下文的内存空间（堆）。所以每次调用时，x都是引用的同一个地址。
	fmt.Println(f1(5), f1(1), f1(1))

	//f2又得到了一个匿名函数，它开辟了一个新的上下文。它里面的变量x，和f1当然就不一样了。
	fmt.Println(f2(1), f2(1))
}
